package oop.core.entity;

import java.util.*;

import oop.core.RunGame;
import oop.core.item.Equipment;
import oop.core.item.EquippableItem;
import oop.core.item.Inventory;
import oop.core.item.Item;
import oop.core.item.OneShotItem;
import oop.core.item.SellableItem;
import oop.core.item.TakeableItem;
import oop.core.item.UsableItem;
import oop.core.map.Location;
import oop.core.map.MovementType;
import oop.core.skill.*;
/**
 * The class to hold all the Avatar specific aspects of the Avatar
 */
public class Avatar extends Entity {
	public int money;
	public Occupation occ;
	
	public Avatar(int money, Occupation occ, String imageID, String name, int direction, Location loc, boolean isVisible, Equipment equipment, Inventory inventory, List<MovementType> movementType, DerivedStats derivedStats)
	{
		super(imageID, name, direction, loc, isVisible, equipment, inventory, movementType, derivedStats, 0);
		this.money = money;
		this.occ = occ;
	}
	public ActiveSkill getDerivedActiveSkill(int position, EquippableItem e){
		return occ.getDerivedActiveSkill(position, e);
	}
	public InteractiveSkill getInteractiveSkill(int position){
		return occ.getInteractiveSkill(position);
	}
	public void interactWithEntity(){
		//todo
	}
	public void useSkill(Skill s){
		//todo
	}
	
	public TakeableItem getItem(int i){
		return inventory.getItem(i);
	}
	public TakeableItem removeItem(TakeableItem i)
	{
		return this.inventory.removeItem(i);
	}
	
	public TakeableItem removeItem(int i)
	{
		return this.inventory.removeItem(i);
	}
	
	public boolean addItem(TakeableItem i){
		return inventory.addItem(i);
	}
	public int getMoney() {
		return money;
	}
	public void setMoney(int money) {
		this.money = money;
	}
	public Occupation getOcc() {
		return occ;
	}
	public void setOcc(Occupation occ) {
		this.occ = occ;
	}
	
	/**
	 * Levels the Avatar up based on the Occupation's level up stats.
	 */
	public void doLevelUp(int levels)
	{
		derStats.doLevelUp(occ.getLevelUpStats());
	}
	
	public void takeLives(int lives){
		die(lives);
	}
	
	public void die(int lives)
	{
		derStats.die(lives);
	}
	
	public EquippableItem getWeapon()
	{
		return equipment.getWeapon();
	}
	
	public void useItem(UsableItem item)
	{
		RunGame.println("You used " + item.getName());
		derStats.buffStats(item.getStats());
	}
	public void useItem(OneShotItem item)
	{
		RunGame.println("You used " + item.getName());
		derStats.buffStats(item.getStats());
	}
	
	/**
	 * Equips an Item and increases stats based on it 
	 * @return
	 */
	public boolean equipItem(EquippableItem item)
	{
		
		boolean ret = equipment.equipItem(item,occ);
		RunGame.println("You equipped " + item.getName());
		if (ret)
		{
			derStats.buffStats(item.getStats());
		}
		return ret;
	}
	
	/**
	 * Used to attack another entity
	 */
	public void attackEntity(Entity e){
		
		List<PassiveSkill> slist = occ.getPassiveSkill();
		
		PassiveSkill p = null;
		
		int obsmod = 0;
		
		for(PassiveSkill ps : slist){
			if(ps.getName() == "Observation")
			{
				obsmod = 10 - ps.getSkillLevel();
				break;
			}
		}
		
		for(PassiveSkill ps : slist){
			if(ps.getName() == getWeapon().getEquipmentType())
			{
				p = ps;
				break;
			}
		}
		if(p == null)
		{ //Then Brawling might be in the passive skill list and should be used
			int ret = 0;
			for(PassiveSkill ps : slist){
				if(ps.getName() == "Brawling")
				{
					ret = ps.getSkillLevel();
					break;
				}
			}
			
			int dmgdone = derStats.calcDamage(ret);
			RunGame.println("You did" + (dmgdone - obsmod) + "-" + (dmgdone + obsmod) + " damage.");
			e.takeDamage(dmgdone);
			
		} else
		{
			
			int dmgdone = derStats.calcDamage(p.getSkillLevel());
			RunGame.println("You did" + (dmgdone - obsmod) + "-" + (dmgdone + obsmod) + " damage.");
			e.takeDamage(dmgdone);
		}
	}
	
	/**
	 * Unequips an Item and decreases stats based on it 
	 * @return
	 */
	public void unEquipItem(int index)
	{
		EquippableItem item = equipment.getItem(index);
		if(item == null)
		{
			return;
		}
		if(inventory.canAdd(item))
		{
			RunGame.println("You unequipped " + item.getName());
			this.equipment.unEquip(index);
			derStats.debuffStats(item.getStats());
			inventory.addItem(item);
		}
		
	}
	
	/**
	 * Takes care of purchasing an item. It adds the item to Inventory and reduces the Avatar's money
	 * @param item 
	 * @return
	 */
	public boolean buy(SellableItem item)
	{
		if (item==null){
			return false;
		}
		if (item.getPrice()>this.money){
			return false;
		}
		this.addItem(item);
		
		List<PassiveSkill> slist = occ.getPassiveSkill();
		Double bargainmod = 1.0;
		
		for(PassiveSkill ps : slist){
			if(ps.getName() == "Bargain")
			{
				bargainmod = 1 - (.2 * ps.getSkillLevel());
				break;
			}
		}
		
		Double price = item.getPrice() * bargainmod;
		
		this.money = this.money - price.intValue();
		RunGame.println("You bought " + item.getName() + " for " + price );
		
		return true;
	}
	
	/**
	 * Takes care of selling an item. It removes the item from Inventory and increases the Avatar's money
	 * @param item 
	 * @return
	 */
	public SellableItem sell(int i)
	{
		TakeableItem item = inventory.getItem(i);
		if(item == null)
		{
			return null;
		}
		if(item instanceof SellableItem){
			this.money=this.money+((SellableItem)item).getPrice();
			removeItem(i);
			RunGame.println("You sold " + item.getName() + " for " + ((SellableItem)item).getPrice() );
			return (SellableItem)item;
		}
		return null;
	}
	
	 public void gainEXP(int exp){
		 this.derStats.giveEXP(exp);
	 }
	 
	 public void gainLives(int lives){
		 this.derStats.setLives(this.derStats.getLives()+lives);
	 }
	
	 public void loseLives(int lives){
		 this.derStats.setLives(this.derStats.getLives()-lives);
	 }
	 
	 public int getLives(){
		 return this.derStats.getLives();
	 }
	 
	 public long getMovement()
	 {
		 return derStats.getMovement();
	 }
	 
	 /**
	  * Toggles if the avatar is visible, for Sneaks
	  */
	 public void toggleHide()
	 {
		 if(this.occ.getName().equals("Sneak"))
		 { 
			 int length = imageID.length();
			 if(imageID.charAt(length-1) == 'i')
			 {
				this.imageID = imageID.substring(0,length-1);
			 }
			 else
			 {
				 this.imageID = imageID + "i";
			 }
		 }
	 }
	 
}
